package com.cskaoyan.thread02.deadlock;

/*
         同步另一个弊端：如果出现了嵌套锁，可能产生死锁

         什么时候会出现嵌套锁？ 如果说，在某些情况下，一个线程需要同时持有多把锁，此时就会出现所谓的嵌套锁
            比如： 某个线程要同时持有两把锁lockA 和 lockB两把锁，换个说法，
            该线程，成功持有lockA锁的情况下，在持有lockB锁

            synchronized (lockA) {

              //当某线程的代码，执行到这里
              synchronized (lockB) {
                // 执行到这里，意味着当前线程在持有lockA锁的情况下，又持有了lockB这把锁，所以此时当前线程就同时持有两把锁
              }
            }


            死锁问题： 死锁是指两个以上的线程在执行过程中，因为争夺资源而产生的一种相互等待的现象



          做一个案例：
           1. 假设，在多线程运行环境下，假设我们的程序要访问一个共享变量
           2. 利用共享变量，计算得到一些结果，但是对于一些计算的中间结果，需要利用打印机打印出来
              而打印机，一次只允许一个线程访问(多线程对打印机的访问，还要做一次线程同步)

           所以很显然，一个线程要完成上述工作，得获取对共享变量的访问权(对被用来同步共享访问，的那把锁加锁)，
           还要获取，对打印机的访问权（对被用来同步访问，打印机的锁成功加锁）

           假设对象共享变量的同步，使用的锁lockA
           假设对象访问打印机的同步，使用的锁lockB

 */
public class Demo1 {
    // lockA锁
    static Object lockA = new Object();
    // lockB锁
    static Object lockB = new Object();


    public static void main(String[] args) {
        ABThread abThread = new ABThread();
        BAThread baThread = new BAThread();

        abThread.start();
        baThread.start();
    }
}

/*
        先加A锁在加B锁
        1. 先对lockA锁加锁，访问共享变量
        2. 在对lockB锁加锁，访问打印机
 */
class ABThread extends Thread {

    @Override
    public void run() {
        synchronized (Demo1.lockA) {
            // 访问共享变量, 计算
            System.out.println("ABThread lockA");
            synchronized (Demo1.lockB) {
                // 访问打印机，打印结果
                System.out.println("ABThread lockB");
            }
        }
    }
}

/*
        先加B锁在加A锁
        1. 先对lockB锁加锁，先获取打印机的访问
        2. 在对lockA锁加锁，访问共享变量，打印计算结果
  */
class BAThread extends Thread {

    @Override
    public void run() {
        synchronized (Demo1.lockB) {
            // 先获取打印机的访问权
            System.out.println("BAThread lockB");
            synchronized (Demo1.lockA) {
                // 访问共享变量，打印计算结果
                System.out.println("BAThread lockA");
            }
        }
    }
}


